home *** CD-ROM | disk | FTP | other *** search
- Subject: v22i027: MIT Athena delete/undelete programs, release 2, Part03/03
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 1670c4cf e787c704 dbea1032 2fa69b6a
-
- Submitted-by: "Jonathan I. Kamens" <jik@pit-manager.mit.edu>
- Posting-number: Volume 22, Issue 27
- Archive-name: undel2/part03
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 3 (of 3)."
- # Contents: delete.c directories.c pattern.c
- # Wrapped by rsalz@papaya.bbn.com on Mon May 7 16:54:02 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'delete.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'delete.c'\"
- else
- echo shar: Extracting \"'delete.c'\" \(13132 characters\)
- sed "s/^X//" >'delete.c' <<'END_OF_FILE'
- X/*
- X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/delete.c,v $
- X * $Author: jik $
- X *
- X * This program is a replacement for rm. Instead of actually deleting
- X * files, it marks them for deletion by prefixing them with a ".#"
- X * prefix.
- X *
- X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
- X * For copying and distribution information, see the file "mit-copyright.h."
- X */
- X
- X#if (!defined(lint) && !defined(SABER))
- X static char rcsid_delete_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/delete.c,v 1.21 89/12/15 04:39:22 jik Exp $";
- X#endif
- X
- X#include <sys/types.h>
- X#include <stdio.h>
- X#include <sys/stat.h>
- X#include <sys/dir.h>
- X#include <strings.h>
- X#include <sys/param.h>
- X#include <sys/file.h>
- X#include <errno.h>
- X#include "errors.h"
- X#include "delete_errs.h"
- X#include "util.h"
- X#include "delete.h"
- X#include "mit-copyright.h"
- X
- X
- X
- X/*
- X * ALGORITHM:
- X *
- X * 1. Parse command-line arguments and set flags.
- X * 2. Call the function delete() for each filename command-line argument.
- X *
- X * delete():
- X *
- X * 1. Can the file be lstat'd?
- X * no -- abort
- X * yes -- continue
- X * 2. Is the file a directory?
- X * yes -- is it a dotfile?
- X * yes -- abort
- X * no -- continue
- X * -- is the filesonly option set?
- X * yes -- is the recursive option specified?
- X * yes -- continue
- X * no -- abort
- X * no -- is the directory empty?
- X * yes -- remove it
- X * no -- is the directoriesonly option set?
- X * yes -- abort
- X * no -- continue
- X * -- is the recursive option specified?
- X * yes -- continue
- X * no -- abort
- X * no -- is the directoriesonly option set?
- X * yes -- abort
- X * no -- continue
- X * 3. If the file is a file, remove it.
- X * 4. If the file is a directory, open it and pass each of its members
- X * (excluding . files) to delete().
- X */
- X
- X
- Xint force, interactive, recursive, noop, verbose, filesonly, directoriesonly;
- Xint emulate_rm;
- Xextern int errno;
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X extern char *optarg;
- X extern int optind;
- X int arg;
- X
- X whoami = lastpart(argv[0]);
- X
- X initialize_del_error_table();
- X
- X force = interactive = recursive = noop = verbose = filesonly =
- X directoriesonly = emulate_rm = 0;
- X while ((arg = getopt(argc, argv, "efirnvFD")) != -1) {
- X switch (arg) {
- X case 'r':
- X recursive++;
- X if (directoriesonly) {
- X fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
- X whoami);
- X usage();
- X exit(1);
- X }
- X break;
- X case 'f':
- X force++;
- X break;
- X case 'i':
- X interactive++;
- X break;
- X case 'n':
- X noop++;
- X break;
- X case 'v':
- X verbose++;
- X break;
- X case 'e':
- X emulate_rm++;
- X break;
- X case 'F':
- X filesonly++;
- X if (directoriesonly) {
- X fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
- X whoami);
- X usage();
- X exit(1);
- X }
- X break;
- X case 'D':
- X directoriesonly++;
- X if (recursive) {
- X fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
- X whoami);
- X usage();
- X exit(1);
- X }
- X if (filesonly) {
- X fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
- X whoami);
- X usage();
- X exit(1);
- X }
- X break;
- X default:
- X usage();
- X exit(1);
- X }
- X }
- X report_errors = ! (force || emulate_rm);
- X
- X if (optind == argc) {
- X if (! force) {
- X fprintf(stderr, "%s: no files specified.\n", whoami);
- X usage();
- X }
- X exit(force ? 0 : 1);
- X }
- X while (optind < argc) {
- X if (delete(argv[optind], 0))
- X error(argv[optind]);
- X optind++;
- X }
- X exit(((! force) && error_occurred) ? 1 : 0);
- X}
- X
- X
- X
- Xusage()
- X{
- X printf("Usage: %s [ options ] filename ...\n", whoami);
- X printf("Options are:\n");
- X printf(" -r recursive\n");
- X printf(" -i interactive\n");
- X printf(" -f force\n");
- X printf(" -n noop\n");
- X printf(" -v verbose\n");
- X printf(" -F files only\n");
- X printf(" -D directories only\n");
- X printf(" -- end options and start filenames\n");
- X printf("-r and -D are mutually exclusive\n");
- X printf("-F and -D are mutually exclusive\n");
- X}
- X
- X
- X
- X
- Xdelete(filename, recursed)
- Xchar *filename;
- Xint recursed;
- X{
- X struct stat stat_buf;
- X int retval;
- X
- X /* can the file be lstat'd? */
- X if (lstat(filename, &stat_buf) == -1) {
- X set_error(errno);
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: %s nonexistent\n", whoami, filename);
- X error(filename);
- X return error_code;
- X }
- X
- X /* is the file a directory? */
- X if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
- X /* is the file a dot file? */
- X if (is_dotfile(lastpart(filename))) {
- X set_error(DELETE_IS_DOTFILE);
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: cannot remove `.' or `..'\n", whoami);
- X error(filename);
- X return error_code;
- X }
- X
- X /* is the filesonly option set? */
- X if (filesonly) {
- X /* is the recursive option specified? */
- X if (recursive) {
- X if (retval = recursive_delete(filename, stat_buf,
- X recursed)) {
- X error(filename);
- X return retval;
- X }
- X }
- X else {
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: %s directory\n", whoami,
- X filename);
- X set_error(DELETE_CANT_DEL_DIR);
- X error(filename);
- X return error_code;
- X }
- X }
- X else {
- X /* is the directory empty? */
- X if ((retval = empty_directory(filename)) < 0) {
- X error(filename);
- X if (! emulate_rm)
- X return error_code;
- X }
- X
- X if (retval > 0) {
- X /* remove it */
- X if (retval = do_move(filename, stat_buf, 0)) {
- X error(filename);
- X return error_code;
- X }
- X }
- X else {
- X /* is the directoriesonly option set? */
- X if (directoriesonly) {
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: %s: Directory not empty\n",
- X whoami, filename);
- X set_error(DELETE_DIR_NOT_EMPTY);
- X error(filename);
- X return error_code;
- X }
- X else {
- X /* is the recursive option specified? */
- X if (recursive) {
- X if (retval = recursive_delete(filename, stat_buf,
- X recursed)) {
- X error(filename);
- X return error_code;
- X }
- X }
- X else {
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: %s not empty\n",
- X whoami, filename);
- X set_error(DELETE_DIR_NOT_EMPTY);
- X error(filename);
- X return error_code;
- X }
- X }
- X }
- X }
- X }
- X else {
- X /* is the directoriesonly option set? */
- X if (directoriesonly) {
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: %s: Not a directory\n", whoami,
- X filename);
- X set_error(DELETE_CANT_DEL_FILE);
- X error(filename);
- X return error_code;
- X }
- X else {
- X if (retval = do_move(filename, stat_buf, 0)) {
- X error(filename);
- X return error_code;
- X }
- X }
- X }
- X return 0;
- X}
- X
- X
- X
- X
- X
- Xempty_directory(filename)
- Xchar *filename;
- X{
- X DIR *dirp;
- X struct direct *dp;
- X
- X dirp = Opendir(filename);
- X if (! dirp) {
- X set_error(errno);
- X error(filename);
- X return -1;
- X }
- X for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- X if (is_dotfile(dp->d_name))
- X continue;
- X if (is_deleted(dp->d_name))
- X continue;
- X else {
- X closedir(dirp);
- X return 0;
- X }
- X }
- X closedir(dirp);
- X return 1;
- X}
- X
- X
- X
- X
- Xrecursive_delete(filename, stat_buf, recursed)
- Xchar *filename;
- Xstruct stat stat_buf;
- Xint recursed;
- X{
- X DIR *dirp;
- X struct direct *dp;
- X int status = 0;
- X char newfile[MAXPATHLEN];
- X int retval = 0;
- X
- X if (interactive && recursed) {
- X printf("%s: remove directory %s? ", whoami, filename);
- X if (! yes()) {
- X set_status(DELETE_NOT_DELETED);
- X return error_code;
- X }
- X }
- X dirp = Opendir(filename);
- X if (! dirp) {
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: %s not changed\n", whoami, filename);
- X set_error(errno);
- X error(filename);
- X return error_code;
- X }
- X for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- X if (is_dotfile(dp->d_name))
- X continue;
- X if (is_deleted(dp->d_name))
- X continue;
- X else {
- X (void) strcpy(newfile, append(filename, dp->d_name));
- X if (! *newfile) {
- X error(filename);
- X status = error_code;
- X }
- X
- X retval = delete(newfile, 1);
- X if (retval) {
- X error(newfile);
- X status = retval;
- X }
- X }
- X }
- X closedir(dirp);
- X
- X if (status && (! emulate_rm)) {
- X set_warning(DELETE_DIR_NOT_EMPTY);
- X error(filename);
- X }
- X else
- X retval = do_move(filename, stat_buf, status);
- X
- X if (retval)
- X status = retval;
- X
- X return status;
- X}
- X
- X
- X
- X
- X
- X
- Xdo_move(filename, stat_buf, subs_not_deleted)
- Xchar *filename;
- Xstruct stat stat_buf;
- Xint subs_not_deleted; /* If the file in question is a directory, and */
- X /* there is something underneath it that hasn't */
- X /* been removed, this will be set to true. */
- X /* The program asks if the user wants to delete */
- X /* the directory, and if the user says yes, */
- X /* checks the value of subs_not_deleted. If */
- X /* it's true, an error results. */
- X /* This is used only when emulating rm. */
- X{
- X char *last;
- X char buf[MAXPATHLEN];
- X char name[MAXNAMLEN];
- X struct stat deleted_buf;
- X
- X (void) strncpy(buf, filename, MAXPATHLEN);
- X last = lastpart(buf);
- X if (strlen(last) > MAXNAMLEN) {
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: %s: filename too long\n", whoami,
- X filename);
- X set_error(ENAMETOOLONG);
- X error(filename);
- X return error_code;
- X }
- X (void) strcpy(name, last);
- X if (strlen(buf) + 3 > MAXPATHLEN) {
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: %s: pathname too long\n", whoami,
- X filename);
- X set_error(ENAMETOOLONG);
- X error(filename);
- X return error_code;
- X }
- X *last = '\0';
- X (void) strcat(buf, ".#");
- X (void) strcat(buf, name);
- X if (interactive) {
- X printf("%s: remove %s? ", whoami, filename);
- X if (! yes()) {
- X set_status(DELETE_NOT_DELETED);
- X return error_code;
- X }
- X }
- X else if ((! force) && ((stat_buf.st_mode & S_IFMT) != S_IFLNK)
- X && access(filename, W_OK)) {
- X if (emulate_rm)
- X printf("%s: override protection %o for %s? ", whoami,
- X stat_buf.st_mode & 0777, filename);
- X else
- X printf("%s: File %s not writeable. Delete anyway? ", whoami,
- X filename);
- X if (! yes()) {
- X set_status(DELETE_NOT_DELETED);
- X return error_code;
- X }
- X }
- X if (emulate_rm && subs_not_deleted) {
- X if (! force)
- X fprintf(stderr, "%s: %s not removed\n", whoami, filename);
- X return 1;
- X }
- X if (noop) {
- X fprintf(stderr, "%s: %s would be removed\n", whoami, filename);
- X return 0;
- X }
- X if ((! lstat(buf, &deleted_buf)) && unlink_completely(buf)) {
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: %s not removed\n", whoami, filename);
- X error(filename);
- X return error_code;
- X }
- X if (rename(filename, buf)) {
- X if (emulate_rm && (! force))
- X fprintf(stderr, "%s: %s not removed\n", whoami, filename);
- X set_error(errno);
- X error(filename);
- X return error_code;
- X }
- X else {
- X if (verbose)
- X fprintf(stderr, "%s: %s removed\n", whoami, filename);
- X return 0;
- X }
- X}
- X
- X
- X
- Xunlink_completely(filename)
- Xchar *filename;
- X{
- X char buf[MAXPATHLEN];
- X struct stat stat_buf;
- X DIR *dirp;
- X struct direct *dp;
- X int status = 0;
- X int retval;
- X
- X if (lstat(filename, &stat_buf)) {
- X set_error(errno);
- X error(filename);
- X return error_code;
- X }
- X
- X if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
- X dirp = Opendir(filename);
- X if (! dirp) {
- X set_error(errno);
- X error(filename);
- X return error_code;
- X }
- X
- X for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- X if (is_dotfile(dp->d_name))
- X continue;
- X (void) strcpy(buf, append(filename, dp->d_name));
- X if (! *buf) {
- X status = error_code;
- X error(filename);
- X continue;
- X }
- X retval = unlink_completely(buf);
- X if (retval) {
- X status = retval;
- X error(filename);
- X }
- X }
- X closedir(dirp);
- X
- X if (status)
- X return status;
- X
- X retval = rmdir(filename);
- X if (retval) {
- X set_error(errno);
- X error(filename);
- X return errno;
- X }
- X }
- X else {
- X retval = unlink(filename);
- X if (retval) {
- X set_error(errno);
- X error(filename);
- X return error_code;
- X }
- X else
- X return 0;
- X }
- X return 0;
- X}
- END_OF_FILE
- if test 13132 -ne `wc -c <'delete.c'`; then
- echo shar: \"'delete.c'\" unpacked with wrong size!
- fi
- # end of 'delete.c'
- fi
- if test -f 'directories.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'directories.c'\"
- else
- echo shar: Extracting \"'directories.c'\" \(14682 characters\)
- sed "s/^X//" >'directories.c' <<'END_OF_FILE'
- X/*
- X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/directories.c,v $
- X * $Author: jik $
- X *
- X * This program is part of a package including delete, undelete,
- X * lsdel, expunge and purge. The software suite is meant as a
- X * replacement for rm which allows for file recovery.
- X *
- X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
- X * For copying and distribution information, see the file "mit-copyright.h."
- X */
- X
- X#if !defined(lint) && !defined(SABER)
- X static char rcsid_directories_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/directories.c,v 1.15 89/11/22 21:32:24 jik Exp $";
- X#endif
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <sys/param.h>
- X#include <sys/dir.h>
- X#include <strings.h>
- X#include <errno.h>
- X#include <com_err.h>
- X#include "delete_errs.h"
- X#include "directories.h"
- X#include "util.h"
- X#include "mit-copyright.h"
- X#include "errors.h"
- X
- Xextern char *realloc();
- Xextern long time();
- Xextern int errno;
- X
- Xstatic filerec root_tree;
- Xstatic filerec cwd_tree;
- X
- Xvoid free_leaf();
- X
- X /* These are not static because external routines need to be able to */
- X /* access them. */
- Xtime_t current_time;
- X
- X
- Xstatic filerec default_cwd = {
- X "",
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X False,
- X False,
- X {0}
- X};
- X
- Xstatic filerec default_root = {
- X "/",
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X False,
- X False,
- X {0}
- X};
- X
- Xstatic filerec default_directory = {
- X "",
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X False,
- X False,
- X {0}
- X};
- X
- Xstatic filerec default_file = {
- X "",
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X (filerec *) NULL,
- X False,
- X False,
- X {0}
- X};
- X
- X
- Xfilerec *get_root_tree()
- X{
- X return(&root_tree);
- X}
- X
- X
- X
- Xfilerec *get_cwd_tree()
- X{
- X return(&cwd_tree);
- X}
- X
- X
- Xint initialize_tree()
- X{
- X int retval;
- X
- X root_tree = default_root;
- X cwd_tree = default_cwd;
- X
- X current_time = time((time_t *)0);
- X if (retval = get_specs(".", &cwd_tree.specs, FOLLOW_LINKS)) {
- X error("get_specs on .");
- X return retval;
- X }
- X if (retval = get_specs("/", &root_tree.specs, FOLLOW_LINKS)) {
- X error("get_specs on /");
- X return retval;
- X }
- X return 0;
- X}
- X
- X
- Xint add_path_to_tree(path, leaf)
- Xchar *path;
- Xfilerec **leaf;
- X{
- X filerec *parent;
- X char next_name[MAXNAMLEN];
- X char lpath[MAXPATHLEN], built_path[MAXPATHLEN], *ptr;
- X struct stat specs;
- X int retval;
- X
- X if (retval = get_specs(path, &specs, DONT_FOLLOW_LINKS)) {
- X char error_buf[MAXPATHLEN+14];
- X
- X (void) sprintf(error_buf, "get_specs on %s", path);
- X error(error_buf);
- X return retval;
- X }
- X
- X (void) strcpy(lpath, path); /* we don't want to damage the user's */
- X /* string */
- X ptr = lpath;
- X if (*ptr == '/') {
- X parent = &root_tree;
- X ptr++;
- X (void) strcpy(built_path, "/");
- X }
- X else if (! strncmp(ptr, "./", 2)) {
- X parent = &cwd_tree;
- X ptr += 2;
- X *built_path = '\0';
- X }
- X else {
- X parent = &cwd_tree;
- X *built_path = '\0';
- X }
- X
- X (void) strcpy(next_name, firstpart(ptr, ptr));
- X while (*ptr) {
- X (void) strcat(built_path, next_name);
- X if (retval = add_directory_to_parent(parent, next_name, False,
- X &parent)) {
- X error("add_directory_to_parent");
- X return retval;
- X }
- X (void) strcpy(next_name, firstpart(ptr, ptr));
- X if (retval = get_specs(built_path, &parent->specs, FOLLOW_LINKS)) {
- X char error_buf[MAXPATHLEN+14];
- X
- X (void) sprintf(error_buf, "get_specs on %s", built_path);
- X error(error_buf);
- X return retval;
- X }
- X (void) strcat(built_path, "/");
- X }
- X if ((specs.st_mode & S_IFMT) == S_IFDIR) {
- X retval = add_directory_to_parent(parent, next_name, True, leaf);
- X if (retval) {
- X error("add_directory_to_parent");
- X return retval;
- X }
- X }
- X else {
- X retval = add_file_to_parent(parent, next_name, True, leaf);
- X if (retval) {
- X error("add_file_to_parent");
- X return retval;
- X }
- X }
- X
- X (*leaf)->specs = specs;
- X
- X return 0;
- X}
- X
- X
- X
- X
- Xint get_specs(path, specs, follow)
- Xchar *path;
- Xstruct stat *specs;
- Xint follow; /* follow symlinks or not? */
- X{
- X int status;
- X
- X if (strlen(path)) if ((path[strlen(path) - 1] == '/') &&
- X (strlen(path) != 1))
- X path[strlen(path) - 1] = '\0';
- X if (follow == FOLLOW_LINKS)
- X status = stat(path, specs);
- X else
- X status = lstat(path, specs);
- X
- X if (status) {
- X set_error(errno);
- X error(path);
- X return error_code;
- X }
- X
- X return 0;
- X}
- X
- X
- X
- Xfilerec *next_leaf(leaf)
- Xfilerec *leaf;
- X{
- X filerec *new;
- X
- X if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
- X new = first_in_directory(leaf);
- X if (new)
- X return(new);
- X new = next_directory(leaf);
- X return(new);
- X }
- X else {
- X new = next_in_directory(leaf);
- X return(new);
- X }
- X}
- X
- X
- Xfilerec *next_specified_leaf(leaf)
- Xfilerec *leaf;
- X{
- X while (leaf = next_leaf(leaf))
- X if (leaf->specified)
- X return(leaf);
- X return((filerec *) NULL);
- X}
- X
- X
- Xfilerec *next_directory(leaf)
- Xfilerec *leaf;
- X{
- X filerec *ret;
- X if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
- X leaf = leaf->parent;
- X if (leaf)
- X ret = leaf->next;
- X else
- X ret = (filerec *) NULL;
- X if (ret) if (ret->freed)
- X ret = next_directory(ret);
- X return(ret);
- X}
- X
- X
- Xfilerec *next_specified_directory(leaf)
- Xfilerec *leaf;
- X{
- X while (leaf = next_directory(leaf))
- X if (leaf->specified)
- X return(leaf);
- X return ((filerec *) NULL);
- X}
- X
- X
- X
- Xfilerec *next_in_directory(leaf)
- Xfilerec *leaf;
- X{
- X filerec *ret;
- X
- X if (leaf->next)
- X ret = leaf->next;
- X else if (((leaf->specs.st_mode & S_IFMT) != S_IFDIR) && leaf->parent)
- X ret = leaf->parent->dirs;
- X else
- X ret = (filerec *) NULL;
- X if (ret) if (ret->freed)
- X ret = next_in_directory(ret);
- X return (ret);
- X}
- X
- X
- X
- X
- Xfilerec *next_specified_in_directory(leaf)
- Xfilerec *leaf;
- X{
- X while (leaf = next_in_directory(leaf))
- X if (leaf->specified)
- X return(leaf);
- X return ((filerec *) NULL);
- X}
- X
- X
- X
- Xfilerec *first_in_directory(leaf)
- Xfilerec *leaf;
- X{
- X filerec *ret;
- X
- X if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
- X ret = (filerec *) NULL;
- X else if (leaf->files)
- X ret = leaf->files;
- X else if (leaf->dirs)
- X ret = leaf->dirs;
- X else
- X ret = (filerec *) NULL;
- X if (ret) if (ret->freed)
- X ret = next_in_directory(ret);
- X return(ret);
- X}
- X
- X
- Xfilerec *first_specified_in_directory(leaf)
- Xfilerec *leaf;
- X{
- X leaf = first_in_directory(leaf);
- X if (! leaf)
- X return((filerec *) NULL);
- X
- X if (leaf->specified)
- X return(leaf);
- X else
- X leaf = next_specified_in_directory(leaf);
- X return (leaf);
- X}
- X
- X
- Xvoid print_paths_from(leaf)
- Xfilerec *leaf;
- X{
- X char buf[MAXPATHLEN];
- X
- X printf("%s\n", get_leaf_path(leaf, buf));
- X if (leaf->dirs)
- X print_paths_from(leaf->dirs);
- X if (leaf->files)
- X print_paths_from(leaf->files);
- X if (leaf->next)
- X print_paths_from(leaf->next);
- X}
- X
- X
- Xvoid print_specified_paths_from(leaf)
- Xfilerec *leaf;
- X{
- X char buf[MAXPATHLEN];
- X
- X if (leaf->specified)
- X printf("%s\n", get_leaf_path(leaf, buf));
- X if (leaf->dirs)
- X print_specified_paths_from(leaf->dirs);
- X if (leaf->files)
- X print_specified_paths_from(leaf->files);
- X if (leaf->next)
- X print_specified_paths_from(leaf->next);
- X}
- X
- X
- Xint add_file_to_parent(parent, name, specified, last)
- Xfilerec *parent, **last;
- Xchar *name;
- XBoolean specified;
- X{
- X filerec *files;
- X
- X *last = files = (filerec *) NULL;
- X files = parent->files;
- X while (files) {
- X if (! strcmp(files->name, name))
- X break;
- X *last = files;
- X files = files->next;
- X }
- X if (files) {
- X files->specified = (files->specified || specified);
- X *last = files;
- X return 0;
- X }
- X if (*last) {
- X (*last)->next = (filerec *) Malloc((unsigned) sizeof(filerec));
- X if (! (*last)->next) {
- X set_error(errno);
- X error("Malloc");
- X return error_code;
- X }
- X *(*last)->next = default_file;
- X (*last)->next->previous = *last;
- X (*last)->next->parent = parent;
- X (*last) = (*last)->next;
- X }
- X else {
- X parent->files = (filerec *) Malloc(sizeof(filerec));
- X if (! parent->files) {
- X set_error(errno);
- X error("Malloc");
- X return error_code;
- X }
- X *parent->files = default_file;
- X parent->files->parent = parent;
- X parent->files->previous = (filerec *) NULL;
- X *last = parent->files;
- X }
- X (void) strcpy((*last)->name, name);
- X (*last)->specified = specified;
- X return 0;
- X}
- X
- X
- X
- X
- X
- Xint add_directory_to_parent(parent, name, specified, last)
- Xfilerec *parent, **last;
- Xchar *name;
- XBoolean specified;
- X{
- X filerec *directories;
- X
- X *last = (filerec *) NULL;
- X directories = parent->dirs;
- X while (directories) {
- X if (! strcmp(directories->name, name))
- X break;
- X (*last) = directories;
- X directories = directories->next;
- X }
- X if (directories) {
- X directories->specified = (directories->specified || specified);
- X *last = directories;
- X return 0;
- X }
- X if (*last) {
- X (*last)->next = (filerec *) Malloc(sizeof(filerec));
- X if (! (*last)->next) {
- X set_error(errno);
- X error("Malloc");
- X return error_code;
- X }
- X *(*last)->next = default_directory;
- X (*last)->next->previous = *last;
- X (*last)->next->parent = parent;
- X (*last) = (*last)->next;
- X }
- X else {
- X parent->dirs = (filerec *) Malloc(sizeof(filerec));
- X if (! parent->dirs) {
- X set_error(errno);
- X error("Malloc");
- X return error_code;
- X }
- X *parent->dirs = default_directory;
- X parent->dirs->parent = parent;
- X parent->dirs->previous = (filerec *) NULL;
- X (*last) = parent->dirs;
- X }
- X (void) strcpy((*last)->name, name);
- X (*last)->specified = specified;
- X return 0;
- X}
- X
- X
- X
- X
- X
- Xvoid free_leaf(leaf)
- Xfilerec *leaf;
- X{
- X leaf->freed = True;
- X if (! (leaf->dirs || leaf->files)) {
- X if (leaf->previous)
- X leaf->previous->next = leaf->next;
- X if (leaf->next)
- X leaf->next->previous = leaf->previous;
- X if (leaf->parent) {
- X if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
- X if (leaf->parent->dirs == leaf) {
- X leaf->parent->dirs = leaf->next;
- X if (leaf->parent->freed)
- X free_leaf(leaf->parent);
- X }
- X }
- X else {
- X if (leaf->parent->files == leaf) {
- X leaf->parent->files = leaf->next;
- X if (leaf->parent->freed)
- X free_leaf(leaf->parent);
- X }
- X }
- X free((char *) leaf);
- X }
- X }
- X}
- X
- X
- X
- Xint find_child(directory, name, child)
- Xfilerec *directory, **child;
- Xchar *name;
- X{
- X filerec *ptr;
- X
- X *child = (filerec *) NULL;
- X if ((directory->specs.st_mode & S_IFMT) != S_IFDIR)
- X return DIR_NOT_DIRECTORY;
- X ptr = directory->dirs;
- X while (ptr)
- X if (strcmp(ptr->name, name))
- X ptr = ptr->next;
- X else
- X break;
- X if (ptr) {
- X *child = ptr;
- X return DIR_MATCH;
- X }
- X ptr = directory->files;
- X while (ptr)
- X if (strcmp(ptr->name, name))
- X ptr = ptr->next;
- X else
- X break;
- X if (ptr) {
- X *child = ptr;
- X return DIR_MATCH;
- X }
- X set_status(DIR_NO_MATCH);
- X return DIR_NO_MATCH;
- X}
- X
- X
- X
- X
- X
- Xint change_path(old_path, new_path)
- Xchar *old_path, *new_path;
- X{
- X char next_old[MAXNAMLEN], next_new[MAXNAMLEN];
- X char rest_old[MAXPATHLEN], rest_new[MAXPATHLEN];
- X int retval;
- X filerec *current;
- X
- X if (*old_path == '/') {
- X current = &root_tree;
- X old_path++;
- X new_path++;
- X }
- X else if (! strncmp(old_path, "./", 2)) {
- X current = &cwd_tree;
- X old_path += 2;
- X new_path += 2;
- X }
- X else
- X current = &cwd_tree;
- X
- X (void) strcpy(next_old, firstpart(old_path, rest_old));
- X (void) strcpy(next_new, firstpart(new_path, rest_new));
- X while (*next_old && *next_new) {
- X retval = find_child(current, next_old, ¤t);
- X if (retval == DIR_MATCH) {
- X if (current) {
- X (void) strcpy(current->name, next_new);
- X current->specified = False;
- X }
- X else {
- X set_error(INTERNAL_ERROR);
- X error("change_path");
- X return error_code;
- X }
- X }
- X else {
- X error("change_path");
- X return retval;
- X }
- X
- X (void) strcpy(next_old, firstpart(rest_old, rest_old));
- X (void) strcpy(next_new, firstpart(rest_new, rest_new));
- X }
- X return 0;
- X}
- X
- X
- Xint get_leaf_path(leaf, leaf_buf)
- Xfilerec *leaf;
- Xchar leaf_buf[]; /* RETURN */
- X{
- X char *name_ptr;
- X
- X name_ptr = Malloc(1);
- X if (! name_ptr) {
- X set_error(errno);
- X error("Malloc");
- X *leaf_buf = '\0';
- X return error_code;
- X }
- X *name_ptr = '\0';
- X do {
- X name_ptr = realloc((char *) name_ptr, (unsigned)
- X (strlen(leaf->name) + strlen(name_ptr) + 2));
- X if (! name_ptr) {
- X set_error(errno);
- X *leaf_buf = '\0';
- X error("realloc");
- X return error_code;
- X }
- X (void) strcpy(leaf_buf, name_ptr);
- X *name_ptr = '\0';
- X if (leaf->parent) if (leaf->parent->parent)
- X (void) strcat(name_ptr, "/");
- X (void) strcat(name_ptr, leaf->name);
- X (void) strcat(name_ptr, leaf_buf);
- X leaf = leaf->parent;
- X } while (leaf);
- X (void) strcpy(leaf_buf, name_ptr);
- X return 0;
- X}
- X
- X
- X
- X
- X
- Xint accumulate_names(leaf, in_strings, num)
- Xfilerec *leaf;
- Xchar ***in_strings;
- Xint *num;
- X{
- X char newname[MAXPATHLEN];
- X char **strings;
- X int retval;
- X
- X strings = *in_strings;
- X if (leaf->specified) {
- X *num += 1;
- X strings = (char **) realloc((char *) strings, (unsigned)
- X (sizeof(char *) * (*num)));
- X if (! strings) {
- X set_error(errno);
- X error("realloc");
- X return error_code;
- X }
- X if (retval = get_leaf_path(leaf, newname)) {
- X error("get_leaf_path");
- X return retval;
- X }
- X (void) convert_to_user_name(newname, newname);
- X strings[*num - 1] = Malloc((unsigned) (strlen(newname) + 1));
- X if (! strings[*num - 1]) {
- X set_error(errno);
- X error("Malloc");
- X return error_code;
- X }
- X (void) strcpy(strings[*num - 1], newname);
- X }
- X if (leaf->files) if (retval = accumulate_names(leaf->files, &strings,
- X num)) {
- X error("accumulate_names");
- X return retval;
- X }
- X if (leaf->dirs) if (retval = accumulate_names(leaf->dirs, &strings,
- X num)) {
- X error("accumulate_names");
- X return retval;
- X }
- X if (leaf->next) if (retval = accumulate_names(leaf->next, &strings,
- X num)) {
- X error("accumulate_names");
- X return retval;
- X }
- X
- X *in_strings = strings;
- X return 0;
- X}
- END_OF_FILE
- if test 14682 -ne `wc -c <'directories.c'`; then
- echo shar: \"'directories.c'\" unpacked with wrong size!
- fi
- # end of 'directories.c'
- fi
- if test -f 'pattern.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'pattern.c'\"
- else
- echo shar: Extracting \"'pattern.c'\" \(23196 characters\)
- sed "s/^X//" >'pattern.c' <<'END_OF_FILE'
- X/*
- X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/pattern.c,v $
- X * $Author: jik $
- X *
- X * This program is part of a package including delete, undelete,
- X * lsdel, expunge and purge. The software suite is meant as a
- X * replacement for rm which allows for file recovery.
- X *
- X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
- X * For copying and distribution information, see the file "mit-copyright.h."
- X */
- X
- X#if (!defined(lint) && !defined(SABER))
- X static char rcsid_pattern_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/pattern.c,v 1.16 90/01/11 04:11:58 jik Exp $";
- X#endif
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/dir.h>
- X#include <sys/param.h>
- X#include <strings.h>
- X#include <sys/stat.h>
- X#include <errno.h>
- X#include <com_err.h>
- X#include "directories.h"
- X#include "pattern.h"
- X#include "util.h"
- X#include "undelete.h"
- X#include "shell_regexp.h"
- X#include "mit-copyright.h"
- X#include "delete_errs.h"
- X#include "errors.h"
- X#include "stack.h"
- X
- Xextern char *realloc();
- Xextern int errno;
- Xextern char *whoami;
- X
- Xvoid free_list();
- X
- X
- X/*
- X * add_arrays() takes pointers to two arrays of char **'s and their
- X * lengths, merges the two into the first by realloc'ing the first and
- X * then free's the second's memory usage.
- X */
- Xint add_arrays(array1, num1, array2, num2)
- Xchar ***array1, ***array2;
- Xint *num1, *num2;
- X{
- X int counter;
- X
- X *array1 = (char **) realloc((char *) *array1, (unsigned)
- X (sizeof(char *) * (*num1 + *num2)));
- X if (! *array1) {
- X set_error(errno);
- X error("realloc");
- X return error_code;
- X }
- X for (counter = *num1; counter < *num1 + *num2; counter++)
- X *(*array1 + counter) = *(*array2 + counter - *num1);
- X free ((char *) *array2);
- X *num1 += *num2;
- X return 0;
- X}
- X
- X
- X
- X
- X
- X
- X/*
- X * Add a string to a list of strings.
- X */
- Xint add_str(strs, num, str)
- Xchar ***strs;
- Xint num;
- Xchar *str;
- X{
- X char **ary;
- X
- X ary = *strs = (char **) realloc((char *) *strs, (unsigned)
- X (sizeof(char *) * (num + 1)));
- X if (! *strs) {
- X set_error(errno);
- X error("realloc");
- X return error_code;
- X }
- X ary[num] = Malloc((unsigned) (strlen(str) + 1));
- X if (! ary[num]) {
- X set_error(errno);
- X error("Malloc");
- X return error_code;
- X }
- X (void) strcpy(ary[num], str);
- X return 0;
- X}
- X
- X
- X
- X
- X
- X/*
- X * Find_matches will behave unpredictably if you try to use it to find
- X * very strange combinations of file types, for example only searching
- X * for undeleted files in the top-level directory, while searching
- X * recursively for deleted files. Basically, there are some conflicts
- X * between options that I don't list here because I don't think I'll
- X * ever need to use those combinations.
- X */
- X/*
- X * Function: find_matches(char *name, int *num_found, char ***found,
- X * int options)
- X *
- X * Requires: name points to a NULL-terminated string, representing a
- X * filename pattern with regular filename characters, path
- X * separators and shell wildcard characters []*?; num_found points
- X * to a valid int memory storage location; found points to a valid
- X * char ** memory storage location.
- X *
- X * Effects: Returns a list of all the files in the file hierarchy that
- X * match the options specified in options and that match name.
- X * Options are:
- X *
- X * FIND_UNDELETED search for and return undeleted files
- X *
- X * FIND_DELETED search for and return deleted files
- X *
- X * FIND_CONTENTS means that if matches are directories (or links to
- X * directories), the contents of the directory should be matched
- X * in addition to the directory itself
- X *
- X * RECURS_FIND_DELETED to search all undeleted subdirectories
- X * recursively of matched directories looking for deleted files
- X *
- X * RECURS_FIND_UNDELETED to search all undeleted subdirectories
- X * recursively of matched directories looking for undeleted files
- X *
- X * RECURS_DELETED to recursively return all contents of deleted
- X * directories in addition to the directories themselves
- X *
- X * FOLLW_LINKS to pursue symlinks to directories and continue down
- X * the referenced directories when searching recursively (if the
- X * initial string is an undeleted symlink it is always traversed;
- X * deleted symlinks are never traversed)
- X *
- X * FOLLW_MOUNTPOINTS to traverse mount points when searching
- X * recursively (if the initial string is a mountpoint it is always
- X * traversed)
- X *
- X * FIND_DOTFILES forces the system to recognize dot files instead of
- X * discarding them when looking for files
- X *
- X * If the first character of name is '/', the search is conducted
- X * absolutely from the root of the hierarchy; else, it is conducted
- X * relative to the current working directory. The number of
- X * matching files is returned in *num_found, and a list of file
- X * names is returned in *found. If there are no errors, the return
- X * value is 0; else the return value represents the error code of
- X * the error which occurred. No matter how many file names are
- X * returned, the memory location addressed in *found is a valid
- X * pointer according to Malloc() and can be released using free()
- X * safely. However, if an error value is returned, the caller
- X * should not attempt to use the values stored in *num_found or
- X * *found.
- X *
- X * Modifies: *num_found, *found.
- X */
- Xint find_matches(name, num_found, found, options)
- Xchar *name;
- Xint *num_found;
- Xchar ***found;
- Xint options;
- X{
- X char **matched_files, **return_files, **recurs_files;
- X int num_matched_files = 0, num_return_files = 0,
- X num_recurs_files = 0;
- X int retval;
- X int i;
- X#ifdef DEBUG
- X int j;
- X#endif
- X int match_options = 0;
- X
- X#ifdef DEBUG
- X fprintf(stderr, "Entering find_matches, name = %s, options = %d.\n",
- X name, options);
- X#endif
- X
- X match_options = options & (FIND_DELETED | FIND_UNDELETED);
- X if (options & (RECURS_FIND_DELETED | RECURS_FIND_UNDELETED |
- X FIND_CONTENTS))
- X match_options |= FIND_UNDELETED;
- X
- X if (! match_options) {
- X set_error(PAT_NO_FILES_REQUESTED);
- X error("find_matches");
- X return error_code;
- X }
- X
- X retval = do_match(name, &num_matched_files, &matched_files,
- X match_options & FIND_UNDELETED,
- X match_options & FIND_DELETED);
- X if (retval) {
- X error(name);
- X return retval;
- X }
- X if (num_matched_files == 0) {
- X *num_found = num_matched_files;
- X *found = matched_files;
- X#ifdef DEBUG
- X fprintf(stderr, "No matches found, returning.\n");
- X#endif
- X return 0;
- X }
- X
- X#ifdef DEBUG
- X fprintf(stderr, "The following matches were found:\n");
- X for (i = 0; i < num_matched_files; i++)
- X fprintf(stderr, " %s\n", matched_files[i]);
- X#endif
- X
- X if (options & RECURS) {
- X return_files = (char **) Malloc(0);
- X if (! return_files) {
- X set_error(errno);
- X error("Malloc");
- X return error_code;
- X }
- X num_return_files = 0;
- X
- X for (i = 0; i < num_matched_files; i++) {
- X
- X retval = do_recurs(matched_files[i], &num_recurs_files,
- X &recurs_files, options);
- X if (retval) {
- X error(matched_files[i]);
- X return retval;
- X }
- X
- X if (num_recurs_files) {
- X retval = add_arrays(&return_files, &num_return_files,
- X &recurs_files, &num_recurs_files);
- X if (retval) {
- X error("add_arrays");
- X return retval;
- X }
- X#ifdef DEBUG
- X fprintf(stderr,
- X "Just added the following to return_files:\n");
- X for (j = num_return_files - num_recurs_files;
- X j < num_return_files; j++)
- X fprintf(stderr, " %s\n", return_files[j]);
- X#endif
- X }
- X
- X if (is_deleted(lastpart(matched_files[i]))) {
- X if (options & FIND_DELETED) {
- X retval = add_str(&return_files, num_return_files,
- X matched_files[i]);
- X if (retval) {
- X error("add_str");
- X return retval;
- X }
- X num_return_files++;
- X#ifdef DEBUG
- X fprintf(stderr, "Just added %s to return_files.\n",
- X return_files[num_return_files-1]);
- X#endif
- X }
- X }
- X else if (options & FIND_UNDELETED) {
- X retval = add_str(&return_files, num_return_files,
- X matched_files[i]);
- X if (retval) {
- X error("add_str");
- X return retval;
- X }
- X num_return_files++;
- X#ifdef DEBUG
- X fprintf(stderr, "Just added %s to return_files.\n",
- X return_files[num_return_files-1]);
- X#endif
- X }
- X }
- X free_list(matched_files, num_matched_files);
- X *num_found = num_return_files;
- X *found = return_files;
- X }
- X else {
- X *num_found = num_matched_files;
- X *found = matched_files;
- X }
- X
- X return 0;
- X}
- X
- X
- X
- X
- X
- X
- X
- X
- X#define string_push(str)\
- X strsize = strlen(str);\
- X retval = push(str, strsize);\
- X if (! retval)\
- X retval |= push(&strsize, sizeof(int));\
- X if (retval) {\
- X error("push");\
- X (void) popall();\
- X return retval;\
- X }
- X#define string_pop(str)\
- X retval = pop(&strsize, sizeof(int));\
- X if (! retval)\
- X retval = pop(str, strsize);\
- X if (! retval)\
- X str[strsize] = '\0'
- X
- X
- X
- X
- X
- X
- X/*
- X * Function: do_match(char *name, int *num_found, char ***found,
- X * Boolean match_undeleted, Boolean match_deleted)
- X *
- X * Requires: name points to a NULL-terminated string, representing a
- X * filename pattern with regular filename characters, path
- X * separators and shell wildcard characters []*?; num_found points
- X * to a valid int memory storage location; found points to a valid
- X * char ** memory storage location.
- X *
- X * Effects: Returns a list of all the files in the file hierarchy that
- X * match name. If match_undeleted is true, will return undeleted
- X * files that match; if match_deleted is true, will return
- X * deleted_files that match. If the first character of name is '/',
- X * the search is conducted absolutely from the root of the
- X * hierarchy; else, it is conducted relative to the current working
- X * directory. The number of matching files is returned in
- X * *num_found, and a list of file names is returned in *found. If
- X * there are no errors, the return value is 0; else the return value
- X * represents the error code of the error which occurred. No matter
- X * how many file names are returned, the memory location addressed
- X * in *found is a valid pointer according to Malloc() and can be
- X * released using free() safely. However, if an error value is
- X * returned, the caller should not attempt to use the values stored
- X * in *num_found or *found.
- X *
- X * Modifies: *num_found, *found.
- X *
- X * Algorithm:
- X *
- X * start:
- X * base = "" or "/",
- X * name = name or name + 1
- X * initialze found and num_found
- X * dirp = Opendir(base)
- X * first = firstpart(name, rest) (assigns rest as side-effect)
- X * if (! *first) {
- X * add string to list if appropriate
- X * return
- X *
- X * loop:
- X * dp = readdir(dirp)
- X * if (! dp) goto updir
- X * compare dp->d_name to first -- match?
- X * yes - goto downdir
- X * no - are we looking for deleted and is dp->d_name deleted?
- X * yes - compare undeleted dp->d_name to first -- match?
- X * yes - goto downdir
- X * no - goto loop
- X * no - goto loop
- X *
- X * downdir:
- X * save dirp, rest, first and base on stack
- X * first = firstpart(rest, rest)
- X * base = dp->d_name appended to base
- X * is first an empty string?
- X * yes - put back dirp, rest, first, base
- X * goto loop
- X * try to open dir base - opens?
- X * yes - goto loop
- X * no - is the error ENOTDIR?
- X * yes - don't worry about it
- X * no - report the error
- X * restore dirp, rest, first, base from stack
- X * goto loop
- X *
- X * updir:
- X * close dirp
- X * restore base, rest, first from stack
- X * STACK_EMPTY?
- X * yes - return from procedure with results
- X * restore dirp from stack
- X * goto loop
- X */
- Xint do_match(name, num_found, found, match_undeleted, match_deleted)
- Xchar *name;
- Xint *num_found;
- Xchar ***found;
- XBoolean match_undeleted, match_deleted;
- X{
- X char base[MAXPATHLEN];
- X struct direct *dp;
- X DIR *dirp;
- X char first[MAXNAMLEN], rest[MAXPATHLEN];
- X int retval;
- X int strsize;
- X
- X#ifdef DEBUG
- X printf("do_match: looking for %s\n", name);
- X#endif
- X
- X /* start: */
- X
- X if (*name == '/') {
- X *base = '/';
- X *(base + 1) = '\0';
- X name++;
- X }
- X else
- X *base = '\0';
- X
- X *found = (char **) Malloc(0);
- X if (! *found) {
- X set_error(errno);
- X error("Malloc");
- X return error_code;
- X }
- X *num_found = 0;
- X
- X dirp = Opendir(base);
- X if (! dirp) {
- X set_error(errno);
- X error(base);
- X return error_code;
- X }
- X (void) strcpy(first, firstpart(name, rest));
- X if ((! *first) && (match_undeleted)) {
- X retval = add_str(found, *num_found, base);
- X if (retval) {
- X error("add_str");
- X (void) popall();
- X return retval;
- X }
- X (*num_found)++;
- X return 0;
- X }
- X
- X while (1) {
- X dp = readdir(dirp);
- X if (! dp) goto updir;
- X
- X retval = reg_cmp(first, dp->d_name);
- X if (retval < 0) {
- X error("reg_cmp");
- X goto updir;
- X }
- X
- X if (retval == REGEXP_MATCH) goto downdir;
- X
- X if (is_deleted(dp->d_name) && match_deleted) {
- X retval = reg_cmp(first, &dp->d_name[2]);
- X if (retval < 0) {
- X error("reg_cmp");
- X goto updir;
- X }
- X
- X if (retval == REGEXP_MATCH)
- X goto downdir;
- X else
- X continue;
- X }
- X else
- X continue;
- X
- X downdir:
- X retval = push(&dirp, sizeof(DIR *));
- X if (retval) {
- X error("push");
- X (void) popall();
- X return retval;
- X }
- X string_push(first);
- X string_push(rest);
- X string_push(base);
- X (void) strcpy(base, append(base, dp->d_name));
- X (void) strcpy(first, firstpart(rest, rest));
- X if (! *first) {
- X if (is_deleted(lastpart(base))) {
- X if (match_deleted) {
- X retval = add_str(found, *num_found, base);
- X if (retval) {
- X error("add_str");
- X (void) popall();
- X return retval;
- X }
- X (*num_found)++;
- X }
- X }
- X else if (match_undeleted) {
- X retval = add_str(found, *num_found, base);
- X if (retval) {
- X error("add_str");
- X (void) popall();
- X return retval;
- X }
- X (*num_found)++;
- X }
- X string_pop(base);
- X string_pop(rest);
- X string_pop(first);
- X (void) pop(&dirp, sizeof(DIR *));
- X continue;
- X }
- X
- X dirp = Opendir(base);
- X if (! dirp) {
- X if (errno != ENOTDIR) {
- X set_error(errno);
- X error(base);
- X }
- X string_pop(base);
- X string_pop(rest);
- X string_pop(first);
- X (void) pop(&dirp, sizeof(DIR *));
- X continue;
- X }
- X else
- X continue;
- X
- X updir:
- X closedir(dirp);
- X string_pop(base);
- X if (retval) {
- X if (retval != STACK_EMPTY) {
- X error("pop");
- X (void) popall();
- X return retval;
- X }
- X return 0;
- X }
- X string_pop(rest);
- X string_pop(first);
- X retval = pop(&dirp, sizeof(DIR *));
- X if (retval) {
- X error("pop");
- X (void) popall();
- X return retval;
- X }
- X continue;
- X }
- X}
- X
- X
- X
- X
- X
- X
- X/*
- X * Function: do_recurs(char *name, int *num_found, char ***found,
- X * int options)
- X *
- X * Requires: name points to a NULL-terminated string, representing a
- X * filename pattern with regular filename characters, path
- X * separators and shell wildcard characters []*?; num_found points
- X * to a valid int memory storage location; found points to a valid
- X * char ** memory storage location.
- X *
- X * Effects: Returns a list of all the files in the file hierarchy that
- X * are underneath the specified file, governed by the options set in
- X * options. Options are as described in the find_matches() description.
- X * RECURS_FIND_DELETED and RECURS_DELETED imply FIND_DELETED.
- X * RECURS_FIND_UNDELETED implies FIND_UNDELETED.
- X *
- X * Modifies: *num_found, *found.
- X *
- X * Algorithm:
- X *
- X * start:
- X * initialze found and num_found
- X * strcopy(base, name)
- X * dirp = Opendir(base)
- X * check if we just opened a deleted symlink and return if we did
- X * check RECURS options and set FIND options as appropriate
- X *
- X * loop:
- X * dp = readdir(dirp)
- X * if (! dp) goto updir
- X * is dp deleted?
- X * yes - is FIND_DELETED set?
- X * yes - add to list
- X * is RECURS_DELETED set?
- X * yes - goto downdir
- X * no - goto loop
- X * no - goto loop
- X * no - is FIND_UNDELETED set?
- X * yes - is the file a dotfile?
- X * yes - is FIND_DOTFILES set?
- X * yes - add to list
- X * goto loop
- X * no - add to list
- X * are RECURS_FIND_DELETED and FIND_DELETED set?
- X * yes - goto downdir
- X * is RECURS_FIND_UNDELETED set?
- X * yes - goto downdir
- X * no - goto loop
- X * no - goto loop
- X *
- X * downdir:
- X * save dirp, base on stack
- X * base = dp->d_name appended to base
- X * try to open base -- opens?
- X * yes - is FOLLW_LINKS set?
- X * yes - is it deleted?
- X * yes - is it a link?
- X * yes - close the directory
- X * restore base and dirp
- X * goto loop
- X * no - is it a link?
- X * yes - close the directory
- X * restore base and dirp
- X * goto loop
- X * is FOLLW_MOUNTPOINTS set?
- X * no - is it a mountpoint?
- X * yes - close the directory
- X * restore base and dirp
- X * goto loop
- X * no - is the error ENOTDIR?
- X * yes - don't worry about it
- X * no - report the error
- X * restore base and dirp
- X * goto loop
- X *
- X * updir:
- X * close dirp
- X * restore base from stack
- X * STACK_EMPTY?
- X * yes - return from procedure with results
- X * restore dirp from stack
- X * goto loop
- X */
- Xint do_recurs(name, num_found, found, options)
- Xchar *name;
- Xint *num_found;
- Xchar ***found;
- Xint options;
- X{
- X char base[MAXPATHLEN];
- X struct direct *dp;
- X DIR *dirp;
- X int retval;
- X int strsize;
- X struct stat statbuf;
- X int use_stat;
- X
- X#ifdef DEBUG
- X fprintf(stderr, "do_recurs: opening %s\n", name);
- X#endif
- X
- X /* start: */
- X
- X *found = (char **) Malloc(0);
- X if (! *found) {
- X set_error(errno);
- X error("Malloc");
- X return error_code;
- X }
- X *num_found = 0;
- X strcpy(base, name);
- X
- X /* Never follow deleted symlinks */
- X if (is_deleted(lastpart(base)) && is_link(base, (struct stat *) NULL)) {
- X return 0;
- X }
- X
- X dirp = Opendir(base);
- X if (! dirp) {
- X /* If the problem is that it isn't a directory, just return */
- X /* with zero matches -- the file exists, but cannot be */
- X /* recursively searched. Otherwise, actually signal an */
- X /* error. */
- X if (errno != ENOTDIR) {
- X#ifdef DEBUG
- X fprintf(stderr, "Couldn't open %s.\n", base);
- X#endif
- X set_error(errno);
- X error(base);
- X return error_code;
- X }
- X else
- X return 0;
- X }
- X
- X if (options & (RECURS_FIND_DELETED | RECURS_DELETED))
- X options |= FIND_DELETED;
- X if (options & RECURS_FIND_UNDELETED)
- X options |= FIND_UNDELETED;
- X
- X while (1) {
- X dp = readdir(dirp);
- X if (! dp) goto updir;
- X
- X if (is_deleted(dp->d_name)) {
- X if (options & FIND_DELETED) {
- X retval = add_str(found, *num_found,
- X append(base, dp->d_name));
- X if (retval) {
- X error("add_str");
- X (void) popall();
- X return retval;
- X }
- X (*num_found)++;
- X if (options & RECURS_DELETED)
- X goto downdir;
- X else
- X continue;
- X }
- X else
- X continue;
- X }
- X
- X if (options & FIND_UNDELETED) {
- X if (is_dotfile(dp->d_name)) {
- X if (options & FIND_DOTFILES) {
- X retval = add_str(found, *num_found,
- X append(base, dp->d_name));
- X if (retval) {
- X error("add_str");
- X (void) popall();
- X return retval;
- X }
- X }
- X continue;
- X }
- X else {
- X retval = add_str(found, *num_found,
- X append(base, dp->d_name));
- X if (retval) {
- X error("add_str");
- X (void) popall();
- X return retval;
- X }
- X (*num_found)++;
- X }
- X }
- X
- X if (! is_dotfile(dp->d_name)) {
- X if (options & RECURS_FIND_DELETED)
- X goto downdir;
- X if (options & RECURS_FIND_UNDELETED)
- X goto downdir;
- X }
- X
- X continue;
- X
- X
- X downdir:
- X retval = push(&dirp, sizeof(DIR *));
- X if (retval) {
- X error("push");
- X (void) popall();
- X return retval;
- X }
- X string_push(base);
- X (void) strcpy(base, append(base, dp->d_name));
- X
- X /*
- X * Originally, I did an Opendir() right at the start and
- X * then only checked things if the Opendir resulted in an
- X * error. However, this is inefficient, because the
- X * Opendir() procedure works by first calling open() on the
- X * file, and *then* calling fstat on the file descriptor
- X * that is returned. since most of the time we will be
- X * trying to open things that are not directory, it is much
- X * more effecient to do the stat first here and to do the
- X * Opendir only if the stat results are satisfactory.
- X */
- X use_stat = (options & FOLLW_LINKS) && (! is_deleted(lastpart(base)));
- X if (use_stat)
- X retval = stat(base, &statbuf);
- X else
- X retval = lstat(base, &statbuf);
- X if (retval == -1) {
- X set_error(errno);
- X error(base);
- X string_pop(base);
- X (void) pop(&dirp, sizeof(DIR *));
- X continue;
- X }
- X /* It's not a directory, so punt it and continue. */
- X if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
- X string_pop(base);
- X (void) pop(&dirp, sizeof(DIR *));
- X continue;
- X }
- X
- X /* Actually try to open it. */
- X dirp = Opendir(base);
- X if (! dirp) {
- X set_error(errno);
- X error(base);
- X string_pop(base);
- X (void) pop(&dirp, sizeof(DIR *));
- X continue;
- X }
- X
- X if (! (options & FOLLW_MOUNTPOINTS)) {
- X if (is_mountpoint(base, use_stat ? (struct stat *) NULL :
- X &statbuf)) {
- X closedir(dirp);
- X set_warning(PAT_IS_MOUNT);
- X error(base);
- X string_pop(base);
- X (void) pop(&dirp, sizeof(DIR *));
- X continue;
- X }
- X#ifdef DEBUG
- X else {
- X fprintf(stderr,
- X "do_recurs: %s isn't a mountpoint, following.\n",
- X base);
- X }
- X#endif
- X }
- X#ifdef DEBUG
- X printf("do_recurs: opening %s\n", base);
- X#endif
- X continue;
- X
- X updir:
- X closedir(dirp);
- X string_pop(base);
- X if (retval) {
- X if (retval != STACK_EMPTY) {
- X error("pop");
- X (void) popall();
- X return retval;
- X }
- X return 0;
- X }
- X retval = pop(&dirp, sizeof(DIR *));
- X if (retval) {
- X error("pop");
- X (void) popall();
- X return retval;
- X }
- X continue;
- X }
- X}
- X
- X
- Xvoid free_list(list, num)
- Xchar **list;
- Xint num;
- X{
- X int i;
- X
- X for (i = 0; i < num; i++)
- X free(list[i]);
- X
- X free((char *) list);
- X}
- X
- X
- X
- X
- X
- X
- X/*
- X * returns true if the filename has no globbing wildcards in it. That
- X * means no non-quoted question marks, asterisks, or open square
- X * braces. Assumes a null-terminated string, and a valid globbing
- X */
- Xint no_wildcards(name)
- Xchar *name;
- X{
- X do {
- X switch (*name) {
- X case '\\':
- X name++;
- X break;
- X case '?':
- X return(0);
- X case '*':
- X return(0);
- X case '[':
- X return(0);
- X }
- X } while (*++name);
- X return(1);
- X}
- END_OF_FILE
- if test 23196 -ne `wc -c <'pattern.c'`; then
- echo shar: \"'pattern.c'\" unpacked with wrong size!
- fi
- # end of 'pattern.c'
- fi
- echo shar: End of archive 3 \(of 3\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- exit 0 # Just in case...
-